#include "mainwindow.h"
#include "constraintswindow.h"
#include "aboutdialog.h"
#include <gtkmm/main.h>
#include <sstream>
#include "../logger.h"
#include "../bureaucrat.h"
#include "../course.h"
#include "../registrar.h"

MainWindow::MainWindow(BaseObjectType* cobject,
					   const Glib::RefPtr<Gnome::Glade::Xml>& ui_xml)
	: Gtk::Window(cobject),
	  first_button_(0),
	  back_button_(0),
	  forward_button_(0),
	  last_button_(0),
	  register_button_(0),
	  constraints_button_(0),
	  quit_button_(0),
	  schedule_number_label_(0),
	  schedule_count_label_(0),
	  schedule_treeview_(0),
	  statusbar_(0),
      view_mode_group_(0),
      courses_complete_menuitem_(0),
      schedule_suggestion_menuitem_(0),
      help_about_menuitem_(0)
{
	// connect a handler to the delete-event signal, which is sent when the
	// user closes the window
	signal_delete_event().connect(
		sigc::mem_fun(*this, &MainWindow::on_delete_event));

	// initialize and set up child widgets
	ui_xml->get_widget("first_button", first_button_);
	first_button_->signal_clicked().connect(
		sigc::mem_fun(*this, &MainWindow::on_first));
	ui_xml->get_widget("back_button", back_button_);
	back_button_->signal_clicked().connect(
		sigc::mem_fun(*this, &MainWindow::on_back));
	ui_xml->get_widget("forward_button", forward_button_);
	forward_button_->signal_clicked().connect(
		sigc::mem_fun(*this, &MainWindow::on_forward));
	ui_xml->get_widget("last_button", last_button_);
	last_button_->signal_clicked().connect(
		sigc::mem_fun(*this, &MainWindow::on_last));
	ui_xml->get_widget("register_button", register_button_);
	register_button_->signal_clicked().connect(
		sigc::mem_fun(*this, &MainWindow::on_register));
	ui_xml->get_widget("quit_button", quit_button_);
	ui_xml->get_widget("constraints_button", constraints_button_);
	constraints_button_->signal_clicked().connect(
		sigc::mem_fun(*this, &MainWindow::on_constraints));
	quit_button_->signal_clicked().connect(
		sigc::mem_fun(*this, &MainWindow::on_quit));
	ui_xml->get_widget("courses_complete_menuitem", courses_complete_menuitem_);
	courses_complete_menuitem_->signal_activate().connect(
		sigc::mem_fun(*this, &MainWindow::on_courses_complete_activate));
	ui_xml->get_widget("schedule_suggestion_menuitem", schedule_suggestion_menuitem_);
	schedule_suggestion_menuitem_->signal_activate().connect(
		sigc::mem_fun(*this, &MainWindow::on_schedule_suggestion_activate));
	ui_xml->get_widget("help_about_menuitem", help_about_menuitem_);
	help_about_menuitem_->signal_activate().connect(
		sigc::mem_fun(*this, &MainWindow::on_help_about_activate));
	ui_xml->get_widget("schedule_number_label", schedule_number_label_);
	ui_xml->get_widget("schedule_count_label", schedule_count_label_);
	ui_xml->get_widget("schedule_treeview", schedule_treeview_);
	ui_xml->get_widget("statusbar", statusbar_);

    const int number_of_courses = 4;
    Student the_student = Registrar::instance()->student();
    the_student.setCourseCount(number_of_courses);
    Registrar::instance()->student(the_student);
    std::ostringstream oss;
    oss << "Number of courses hardcoded to " << number_of_courses << '.';
    Logger::instance()->warning(oss.str(), 3);
    oss.str("");
    oss << number_of_courses << " courses";
    statusbar_->push(oss.str());
    oss.str("");

	init_schedule_view();		// set up tree view:  columns, data etc.
}

MainWindow::~MainWindow()
{
}

/// Helper method for initializing the schedule view.
void MainWindow::init_schedule_view()
{
	// to set up treeview's layout, we initialize it with a TreeStore object,
	// which in turn is set up using the columns object.  we call this list store
	// object the "tree model", since every tree is different depending on its
	// list store layout.
	schedule_treeview_model_ = Gtk::TreeStore::create(
		schedule_treeview_columns_);
	schedule_treeview_->set_model(schedule_treeview_model_);

	// set column headers
	schedule_treeview_->append_column("Name",
									  schedule_treeview_columns_.name);
	schedule_treeview_->append_column("Number",
									  schedule_treeview_columns_.number);
	schedule_treeview_->append_column("Type",
									  schedule_treeview_columns_.type);
    schedule_treeview_->append_column("Professor",
                                      schedule_treeview_columns_.professor);
    schedule_treeview_->append_column("Room",
                                      schedule_treeview_columns_.room);
    schedule_treeview_->append_column("ID",
                                      schedule_treeview_columns_.id);
    schedule_treeview_->append_column("Semester",
                                      schedule_treeview_columns_.semester);
    schedule_treeview_->append_column("Begin",
                                      schedule_treeview_columns_.begin);
    schedule_treeview_->append_column("End",
                                      schedule_treeview_columns_.end);
    schedule_treeview_->append_column("DoW",
                                      schedule_treeview_columns_.dow);
    on_forward();
}

/// Handler for the signal emitted when the user clicks the First button.
void MainWindow::on_first()
{
	Logger::instance()->message("The First button was clicked.", 1);
}

/// Handler for the signal emitted when the user clicks the Back button.
void MainWindow::on_back()
{
	Logger::instance()->message("The Back button was clicked.", 1);
}

/// Handler for the signal emitted when the user clicks the Forward button.
void MainWindow::on_forward()
{
    if( Registrar::instance()->student().getCourseCount() == 0 ) {
		std::ostringstream oss;
		oss << "0 courses requested.  No schedule generated.";
		statusbar_->push(oss.str());
        return;
    }
        
	std::vector<Schedule> schedules = Bureaucrat::instance()->schedules();
    if( schedules.empty() ) {
		std::ostringstream oss;
		oss << "No schedule found.";
        Logger::instance()->message(oss.str(), 1);
		statusbar_->push(oss.str());
        oss.str("");
        oss << "No schedules generated, yet continuing with listing mockup.  ";
        Logger::instance()->warning(oss.str(), 3);
        oss.str("");
        oss << "Remember to change this so the function breaks here.";
        Logger::instance()->warning(oss.str(), 3);
        oss.str("");

        // and now, fill some arbitrary sample data into the treeview
        schedule_treeview_model_->clear();
    
        Gtk::TreeModel::Row parent(*(schedule_treeview_model_->append()));
        parent[schedule_treeview_columns_.name] = "SOEN";
        parent[schedule_treeview_columns_.number] = 229;
        parent[schedule_treeview_columns_.type] = "";
        parent[schedule_treeview_columns_.professor] = "";
        parent[schedule_treeview_columns_.room] = "";
        parent[schedule_treeview_columns_.id] = "";
        parent[schedule_treeview_columns_.semester] = 4;
        parent[schedule_treeview_columns_.begin] = "";
        parent[schedule_treeview_columns_.end] = "";
        parent[schedule_treeview_columns_.dow] = "";
        Gtk::TreeModel::Row child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "SOEN";
        child[schedule_treeview_columns_.number] = 229;
        child[schedule_treeview_columns_.type] = "Lec";
        child[schedule_treeview_columns_.professor] = "Teryl Fancott";
        child[schedule_treeview_columns_.room] = "H-820";
        child[schedule_treeview_columns_.id] = "QA";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "08:45";
        child[schedule_treeview_columns_.end] = "10:00";
        child[schedule_treeview_columns_.dow] = "WF";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "SOEN";
        child[schedule_treeview_columns_.number] = 229;
        child[schedule_treeview_columns_.type] = "Tut";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "SOEN";
        child[schedule_treeview_columns_.number] = 229;
        child[schedule_treeview_columns_.type] = "Lab";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        parent = *(schedule_treeview_model_->append());
        parent[schedule_treeview_columns_.name] = "SOEN";
        parent[schedule_treeview_columns_.number] = 341;
        parent[schedule_treeview_columns_.type] = "";
        parent[schedule_treeview_columns_.professor] = "";
        parent[schedule_treeview_columns_.room] = "";
        parent[schedule_treeview_columns_.id] = "";
        parent[schedule_treeview_columns_.semester] = 4;
        parent[schedule_treeview_columns_.begin] = "";
        parent[schedule_treeview_columns_.end] = "";
        parent[schedule_treeview_columns_.dow] = "";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "SOEN";
        child[schedule_treeview_columns_.number] = 341;
        child[schedule_treeview_columns_.type] = "Tut";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        parent = *(schedule_treeview_model_->append());
        parent[schedule_treeview_columns_.name] = "COMP";
        parent[schedule_treeview_columns_.number] = 346;
        parent[schedule_treeview_columns_.type] = "";
        parent[schedule_treeview_columns_.professor] = "";
        parent[schedule_treeview_columns_.room] = "";
        parent[schedule_treeview_columns_.id] = "";
        parent[schedule_treeview_columns_.semester] = 4;
        parent[schedule_treeview_columns_.begin] = "";
        parent[schedule_treeview_columns_.end] = "";
        parent[schedule_treeview_columns_.dow] = "";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "COMP";
        child[schedule_treeview_columns_.number] = 346;
        child[schedule_treeview_columns_.type] = "Lec";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "COMP";
        child[schedule_treeview_columns_.number] = 346;
        child[schedule_treeview_columns_.type] = "Tut";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        parent = *(schedule_treeview_model_->append());
        parent[schedule_treeview_columns_.name] = "COMP";
        parent[schedule_treeview_columns_.number] = 249;
        parent[schedule_treeview_columns_.type] = "";
        parent[schedule_treeview_columns_.professor] = "";
        parent[schedule_treeview_columns_.room] = "";
        parent[schedule_treeview_columns_.id] = "";
        parent[schedule_treeview_columns_.semester] = 4;
        parent[schedule_treeview_columns_.begin] = "";
        parent[schedule_treeview_columns_.end] = "";
        parent[schedule_treeview_columns_.dow] = "";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "COMP";
        child[schedule_treeview_columns_.number] = 249;
        child[schedule_treeview_columns_.type] = "Lec";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "COMP";
        child[schedule_treeview_columns_.number] = 249;
        child[schedule_treeview_columns_.type] = "Tut";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        child = *(schedule_treeview_model_->append(parent.children()));
        child[schedule_treeview_columns_.name] = "COMP";
        child[schedule_treeview_columns_.number] = 249;
        child[schedule_treeview_columns_.type] = "Lab";
        child[schedule_treeview_columns_.professor] = "";
        child[schedule_treeview_columns_.room] = "";
        child[schedule_treeview_columns_.id] = "";
        child[schedule_treeview_columns_.semester] = 4;
        child[schedule_treeview_columns_.begin] = "";
        child[schedule_treeview_columns_.end] = "";
        child[schedule_treeview_columns_.dow] = "";
        statusbar_->push("Schedule generated.");
        return; // TODO:  remove this line with the above sample rows when cleaning up
    }
    
	schedule_treeview_model_->clear();
    
	Gtk::TreeModel::Row row(*(schedule_treeview_model_->append()));

    std::vector<CourseSection> sections = schedules[0].getCourses();
	for( std::vector<CourseSection>::iterator i = sections.begin();
		 i != sections.end(); ++i ) {
		row[schedule_treeview_columns_.name] = i->getCourse().lock()->getCourseID();
// 		row[schedule_treeview_columns_.number] = 228;
// 		row[schedule_treeview_columns_.type] = "Lec";
		row = *(schedule_treeview_model_->append());
	}
	// chop the extra row
	schedule_treeview_model_->erase(row);
}

/// Handler for the signal emitted when the user clicks the Last button.
void MainWindow::on_last()
{
	Logger::instance()->message("The Last button was clicked.", 1);
}

/// Handler for the signal emitted the user clicks the Register button.
void MainWindow::on_register()
{
	Logger::instance()->message("The Register button was clicked.", 1);
}

/// Handler for the signal emitted the user clicks the Constraints button.
void MainWindow::on_constraints()
{
	Logger::instance()->message("The Constraints button was clicked.", 1);
	Glib::RefPtr<Gnome::Glade::Xml> ui_xml =
		Gnome::Glade::Xml::create("constraints_window.glade");
	ConstraintsWindow* constraints_window = 0;
	ui_xml->get_widget_derived("constraints_window", constraints_window);
	int response = constraints_window->run();

	switch( response ) {
	case Gtk::RESPONSE_ACCEPT: {
        // set constraints in student object
        Student student = Registrar::instance()->student();
        student.setConstraints(constraints_window->constraints());
        Logger::instance()->message("Constraints set.", 1);
        Logger::instance()->warning("Constraints are not saved yet.", 1);
		break;
	}
	default:
		break;
	}
}

/// Handler for the signal emitted when the user clicks the Quit button.
void MainWindow::on_quit()
{
	Gtk::Main::quit();
}

/// Handler for the signal emitted when the user closes the main window.
bool MainWindow::on_delete_event(GdkEventAny*)
{
	on_quit();
	return true;
}

void MainWindow::on_courses_complete_activate()
{
	schedule_treeview_model_->clear();
    schedule_treeview_->remove_all_columns();
	schedule_treeview_->append_column("Name",
                                      schedule_treeview_columns_.name);

	// fill completed courses into the treeview
    Student student(Registrar::instance()->student());
    std::vector<boost::shared_ptr<Course> > courses(student.getCompletedCourses());
	Gtk::TreeModel::Row row(*(schedule_treeview_model_->append()));
	for( std::vector<boost::shared_ptr<Course> >::iterator i = courses.begin();
		 i != courses.end(); ++i ) {
        std::string courseID = (*i)->getCourseID();
		row[schedule_treeview_columns_.name] = courseID;
//		row[schedule_treeview_columns_.number] = 228;
// 		row[schedule_treeview_columns_.type] = "Lec";
		row = *(schedule_treeview_model_->append());
	}
	// chop the extra row
	schedule_treeview_model_->erase(row);
}

void MainWindow::on_schedule_suggestion_activate()
{
    schedule_treeview_->remove_all_columns();
    init_schedule_view();
}

void MainWindow::on_help_about_activate()
{
	Glib::RefPtr<Gnome::Glade::Xml> ui_xml =
		Gnome::Glade::Xml::create("about_dialog.glade");
    AboutDialog* about_dialog = 0;
	ui_xml->get_widget_derived("about_dialog", about_dialog);
    about_dialog->set_transient_for(*this);
    about_dialog->show();
    about_dialog->present();
}
